﻿//此文件用于计算光通量积分
//算法步骤
//先计算高斯低通
//在原图上改进otsu法进行阈值分割
//膨胀大概4-7个像素
//计算连通域
//计算相应的光通量积分
//计算估计光亮度。




#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <thread>
#include "public.h"
#include "FinderData.hpp"


cv::Mat color_mark;//图片颜色标记png
FinderData finderData;
std::string in_pic = R"(C:\Users\17616\Desktop\本科毕设\实验数据记录\2021-5-20\G0_0-F4-0520\G0_0-LD3I2\合成.tiff)";
int main(int argn, const char **argv) {
    destructHelper destructhelper([]() {
        printf("程序退出中。。。。\r\n");
    });
    if (argn == 1) {
        return 0;
    } else if (strcmp(argv[1], "--test") == 0) {
    } else {
        std::cout << "file= " << argv[1] << std::endl;
        in_pic = argv[1];
    }

    cv::Mat in = cv::imread(in_pic, cv::IMREAD_UNCHANGED);
    cv::Mat Blur = cv::imread(GetFilePath(in_pic) + "Blur.tiff", cv::IMREAD_UNCHANGED);
    if (!std::filesystem::exists(GetFilePath(in_pic) + "FinderWorkSpace.xlsx")) {
        std::cout << "缺少  FinderWorkSpace.xlsx" << std::endl;
        system("pause");
        return 0;
    }
    finderData.open(GetFilePath(in_pic) + "FinderWorkSpace.xlsx");
    destructhelper.push_back([&]() {
        finderData.save();
    });
    color_mark = cv::Mat::zeros(in.size(), CV_16U);
    destructhelper.push_back([&]() {
        cv::imwrite(GetFilePath(in_pic) + "FinderWorkSpace.png", color_mark);
    });
    for (int i = 0; i < finderData.size(); ++i) {
        if (finderData("当量", i).value().get<int>() != 0) {
            auto x = finderData("x", i).value().get<int>();
            auto y = finderData("y", i).value().get<int>();
            auto w = finderData("w", i).value().get<int>();
            auto h = finderData("h", i).value().get<int>();
            auto radius = (int) (3 * sqrt(finderData("当量", i).value().get<int>())) | 1;
            auto sigma = (int) (1.5 * sqrt(finderData("当量", i).value().get<int>())) | 1;
//            auto radius = (int) (2.5 * sqrt(w * h)) | 1;
            if (w > 100 || h > 100) {
                continue;
            }

            x += w / 2;
            y += h / 2;
            w = 30;
            h = 30;
            x -= w / 2;
            y -= h / 2;
            cv::Rect ROI_d;
            ROI_d.x = MAX(x - w * 2, 0);
            ROI_d.y = MAX(y - h * 2, 0);
            ROI_d.width = MIN(w * 5, in.size().width - ROI_d.x);
            ROI_d.height = MIN(h * 5, in.size().height - ROI_d.y);

            cv::Mat buf = cv::Mat::zeros(ROI_d.size(), CV_8U);
            cv::Mat buf2 = cv::Mat::zeros(ROI_d.size(), CV_8U);
            cv::Mat buf3 = cv::Mat::zeros(ROI_d.size(), CV_16U);
            cv::Mat buf4 = cv::Mat::zeros(ROI_d.size(), CV_32F);
            //计算改进otsu法
            if (!MyOtsu(in(ROI_d), buf, false)) {
                continue;
            }

            //膨胀
            static cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7, 7));
            cv::dilate(buf, buf2, element);

            //连通域
            int nLabels = cv::connectedComponents(buf2, buf3, 8, CV_16U);
            int select_lablel = 0;//选择的标签
            for (int r = ROI_d.height / 2 - 10; r < ROI_d.height / 2 + 10; ++r) {
                uint16_t *pix_buf3 = (uint16_t *) ((size_t) buf3.data + r * buf3.step) + 65;
                for (int c = ROI_d.width / 2 - 10; c < ROI_d.width / 2 + 10; ++c) {
                    if (*pix_buf3 != 0) {
                        if (select_lablel == 0) {
                            select_lablel = *pix_buf3;
                        } else if (select_lablel == *pix_buf3) {

                        } else {
                            std::cout << Format("[%d] ", finderData("编号", i).value().get<uint16_t>()) << "未定义行为，在损伤点出现了多组连通域，及时处理" << ROI_d << std::endl;
                            continue;
                        }
                    }
                    pix_buf3++;
                }
            }
            if (select_lablel == 0) {
                std::cout << Format("[%d] ", finderData("编号", i).value().get<uint16_t>()) << "未定义行为，未找到损伤点对应的区域" << ROI_d << std::endl;
                continue;
            }

            cv::GaussianBlur(in(ROI_d), buf4, cv::Size(radius, radius), sigma, sigma);
            //当前的标签为select_lablel
            //将颜色状况拷贝并//计算估计光亮度//计算积分
            float phi = 0;
            float phi_sum = 0;
            for (int r = 0; r < ROI_d.height; ++r) {
                uint16_t *pix_buf3 = (uint16_t *) ((size_t) buf3.data + r * buf3.step);
                float *pix_buf4 = (float *) ((size_t) buf4.data + r * buf4.step);
                uint16_t *pix_color_mark = (uint16_t *) ((size_t) color_mark.data + (ROI_d.y + r) * color_mark.step) + ROI_d.x;
                float *pix_Blur = (float *) ((size_t) Blur.data + (ROI_d.y + r) * Blur.step) + ROI_d.x;
                float *pix_in = (float *) ((size_t) in.data + (ROI_d.y + r) * in.step) + ROI_d.x;
                for (int c = 0; c < ROI_d.width; ++c) {
                    if (*pix_buf3 == select_lablel) {
                        if (*pix_color_mark == 0) {
                            *pix_color_mark = finderData("编号", i).value().get<uint16_t>();
                            phi = MAX(phi, *pix_buf4);
                            phi_sum += *pix_in;
                        } else {
                            std::cout << Format("[%d] ", finderData("编号", i).value().get<uint16_t>()) << "未定义行为，有多个损伤点连到一起，及时处理" << ROI_d << std::endl;
                            continue;
                        }
                    }
                    pix_buf3++;
                    pix_buf4++;
                    pix_color_mark++;
                    pix_Blur++;
                    pix_in++;
                }
            }
            finderData("光通量积分", i).value() = phi_sum;
            finderData("光通量估计", i).value() = phi;
//            finderData("光通量估计", i).value() = phi_sum/finderData("当量", i).value().get<uint16_t>();
        }
    }
    return 0;
}